package com.speedchina.permission.security.shiro;

import com.speedchina.common.message.entity.Alert;
import com.speedchina.common.message.service.AlertService;
import com.speedchina.common.message.service.impl.AlertServiceImpl;
import com.speedchina.framework.exception.BException;
import com.speedchina.framework.exception.BaseSqlException;
import com.speedchina.framework.helper.Assert;
import com.speedchina.framework.model.R;
import com.speedchina.permission.base.exception.GlobalExceptionHandler;
import com.speedchina.permission.base.util.WeChatRobot;
import com.speedchina.permission.domain.sys.entity.User;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.AuthorizationException;
import org.postgresql.util.PSQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.io.IOException;


/**
 * shrio相关异常全局捕捉
 *
 * @author Winter
 * @create 2020-11-12 下午2:09
 **/
@ControllerAdvice
public class ShiroExceptionHandler extends GlobalExceptionHandler {
    @Autowired
    AlertService alertService;
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    @ExceptionHandler(value = {AuthorizationException.class})
    public R authorizationException(AuthorizationException e) {
        e.printStackTrace();
        return R.error("无权访问");
    }

    @ResponseBody
    @ExceptionHandler(value = {SecurityException.class})
    public R securityException(SecurityException e) {
        e.printStackTrace();
        return R.error(e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = {AuthenticationException.class})
    public R authenticationException(AuthenticationException e) {
        e.printStackTrace();
        return R.error(e.getMessage());
    }

    @Override
    @ExceptionHandler(Exception.class)
    public R handleException(Exception e) {
        this.sendErrorAlarm(e);
        // 此处解决 pg 数据库在接收 特殊字符 \u0000 段时，触发 'invalid byte sequence for encoding' 的问题
        if(e instanceof PSQLException && (e != null && e.getMessage() != null && e.getMessage().contains("invalid byte sequence for encoding"))){
            e.printStackTrace();
            return R.error("SQL执行异常,请检查参数是否包含特殊字符或SQL语法准确性");
        }
        return R.error(e.getMessage());
    }


    @Override
    protected void sendErrorAlarm(Exception e) {
        StringBuffer str = new StringBuffer("错误类型:");
        String msg = null;
        if(e instanceof BaseSqlException) {
            msg = e.getMessage();
            str.append("数据库错误");
        } else if(e instanceof BException) {
            msg = ((BException) e).getMsg();
            str.append("其他逻辑错误");
        } else{
            msg = e.getMessage() == null ? e.getCause().toString() : e.getLocalizedMessage();
            str.append("未处理异常");
        }
        str.append("\n").append(msg).append("\n");
        User user = SecurityUtils.getLoginUser();
        str.append("操作人:").append(user != null ? user.getUsername() : "未知用户");
        alertService.sendAlert(str.toString(),null);
    }
}
